<script>
import ZxCheckbox from '../../../components/checkbox';
import ZxRadio from '../../../components/radio';
import { isEqual } from '@src/utils/util';

const stopPropagation = e => e.stopPropagation();

export default {
    inject: ['panel'],

    components: {
        ZxCheckbox,
        ZxRadio,
    },

    props: {
        node: {
            required: true,
        },
        nodeId: String,
    },

    computed: {
        config() {
            return this.panel.config;
        },
        isLeaf() {
            return this.node.isLeaf;
        },
        isDisabled() {
            return this.node.isDisabled;
        },
        checkedValue() {
            return this.panel.checkedValue;
        },
        isChecked() {
            return this.node.isSameNode(this.checkedValue);
        },
        inActivePath() {
            return this.isInPath(this.panel.activePath);
        },
        inCheckedPath() {
            if (!this.config.checkStrictly) return false;

            return this.panel.checkedNodePaths
                .some(checkedPath => this.isInPath(checkedPath));
        },
        value() {
            return this.node.getValueByOption();
        },
    },

    methods: {
        handleExpand() {
            const { panel, node, isDisabled, config } = this;
            const { multiple, checkStrictly } = config;

            if (!checkStrictly && isDisabled || node.loading) return;

            if (config.lazy && !node.loaded) {
                panel.lazyLoad(node, () => {
                    // do not use cached leaf value here, invoke this.isLeaf to get new value.
                    const { isLeaf } = this;

                    if (!isLeaf) this.handleExpand();
                    if (multiple) {
                        // if leaf sync checked state, else clear checked state
                        const checked = isLeaf ? node.checked : false;
                        this.handleMultiCheckChange(checked);
                    }
                });
            } else {
                panel.handleExpand(node);
            }
        },

        handleCheckChange() {
            const { panel, value, node } = this;
            panel.handleCheckChange(value);
            panel.handleExpand(node);
        },

        handleMultiCheckChange(checked) {
            this.node.doCheck(checked);
            this.panel.calculateMultiCheckedValue();
        },

        isInPath(pathNodes) {
            const { node } = this;
            const selectedPathNode = pathNodes[node.level - 1] || {};
            return selectedPathNode.uid === node.uid;
        },

        renderPrefix(h) {
            const { isLeaf, isChecked, config } = this;
            const { checkStrictly, multiple } = config;

            if (multiple) {
                return this.renderCheckbox(h);
            } else if (checkStrictly) {
                return this.renderRadio(h);
            } else if (isLeaf && isChecked) {
                return this.renderCheckIcon(h);
            }

            return null;
        },

        renderPostfix(h) {
            const { node, isLeaf } = this;

            if (node.loading) {
                return this.renderLoadingIcon(h);
            } else if (!isLeaf) {
                return this.renderExpandIcon(h);
            }

            return null;
        },

        renderCheckbox(h) {
            const { node, config, isDisabled } = this;
            const events = {
                on: { change: this.handleMultiCheckChange },
                nativeOn: {},
            };

            if (config.checkStrictly) { // when every node is selectable, click event should not trigger expand event.
                events.nativeOn.click = stopPropagation;
            }

            return (
          <zx-checkbox
            value={ node.checked }
            indeterminate={ node.indeterminate }
            disabled={ isDisabled }
            { ...events }
          ></zx-checkbox>
            );
        },

        renderRadio(h) {
            let { checkedValue, value, isDisabled } = this;

            // to keep same reference if value cause radio's checked state is calculated by reference comparision;
            if (isEqual(value, checkedValue)) {
                value = checkedValue;
            }

            return (
          <zx-radio
            value={ checkedValue }
            label={ value }
            disabled={ isDisabled }
            onChange={ this.handleCheckChange }
            nativeOnClick={ stopPropagation }>
            {/* add an empty element to avoid render label */}
            <span></span>
          </zx-radio>
            );
        },

        renderCheckIcon(h) {
            return (
          <i class="zx-icon-check zx-cascader-node__prefix" style="fontSize:14px"></i>
            );
        },

        renderLoadingIcon(h) {
            return (
          <i class="zx-icon-loading zx-cascader-node__postfix" style="fontSize:14px"></i>
            );
        },

        renderExpandIcon(h) {
            return (
          <i class="zx-icon-right zx-cascader-node__postfix" style="fontSize:14px"></i>
            );
        },

        renderContent(h) {
            const { panel, node } = this;
            const render = panel.renderLabelFn;
            const vnode = render
                ? render({ node, data: node.data })
                : null;

            return (
          <span class="zx-cascader-node__label">{ vnode || node.label }</span>
            );
        },
    },

    render(h) {
        const {
            inActivePath,
            inCheckedPath,
            isChecked,
            isLeaf,
            isDisabled,
            config,
            nodeId,
        } = this;
        const { expandTrigger, checkStrictly, multiple } = config;
        const disabled = !checkStrictly && isDisabled;
        const events = { on: {} };

        if (expandTrigger === 'click') {
            events.on.click = this.handleExpand;
        } else {
            events.on.mouseenter = e => {
                this.handleExpand();
                this.$emit('expand', e);
            };
            events.on.focus = e => {
                this.handleExpand();
                this.$emit('expand', e);
            };
        }
        if (isLeaf && !isDisabled && !checkStrictly && !multiple) {
            events.on.click = this.handleCheckChange;
        }

        return (
        <li
          role="menuitem"
          id={ nodeId }
          aria-expanded={ inActivePath }
          tabindex={ disabled ? null : -1 }
          class={{
              'zx-cascader-node': true,
              'is-selectable': checkStrictly,
              'in-active-path': inActivePath,
              'in-checked-path': inCheckedPath,
              'is-active': isChecked,
              'is-disabled': disabled,
          }}
          {...events}>
          { this.renderPrefix(h) }
          { this.renderContent(h) }
          { this.renderPostfix(h) }
        </li>
        );
    },
};
</script>
